package com.lienlq.voicemusic.ui;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Timer;
import java.util.TimerTask;

import android.app.Dialog;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder.AudioSource;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.widget.ImageButton;
import android.widget.TextView;
import android.widget.Toast;

import com.lienlq.voicemusic.R;
import com.lienlq.voicemusic.entity.MusicService;
import com.lienlq.voicemusic.entity.Song;
import com.viewpagerindicator.TitlePageIndicator;

/**
 * @author LeLien
 * 
 */
public class MainActivity extends FragmentActivity {
	public static String ACTIVIY_LOG = "ACTIVIY_LOG";

	private final static String SERVER_IP = "192.168.21.1";
	private final static int SERVER_PORT = 8080;
	
	private static final int RECORDER_AUDIO_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
	private static final int RECORDER_CHANNELS = AudioFormat.CHANNEL_IN_MONO;
	private static final int RECORDER_SAMPLERATE = 16000; 
	private short bitsPerSample = 16;
	
	private final byte SEARCH_TYPE = 1;
	private final byte AUDIO_DATA = 2;
	private final byte PAYLOAD_SIZE = 3;
	
	
	public static byte[] intToByteArray(int a) {
		byte[] ret = new byte[4];
		ret[3] = (byte) (a & 0xFF);
		ret[2] = (byte) ((a >> 8) & 0xFF);
		ret[1] = (byte) ((a >> 16) & 0xFF);
		ret[0] = (byte) ((a >> 24) & 0xFF);
		return ret;
	}

	private int aFormat = RECORDER_AUDIO_FORMAT;
	private int aSource = AudioSource.MIC;
	private AudioRecord audioRecord = null; 
	private byte[] buffer;
	private int bufferSize;

	private Context context;
	private TextView nowPlagTrackTV, nowPlagArtistTV;
	
	
	private int framePeriod;

	protected boolean isRecording = false;
	private short nChannels = 1;
	private ViewPager pager;

	protected int payloadSize;

	private int sampleRate = RECORDER_SAMPLERATE;

	private InetAddress serverAddress;
	private ArrayList<Song> songlist = new ArrayList<Song>();
	private int TIMER_INTERVAL = 120;
	private int timeToRecord = 5;

	private DatagramSocket udpSocket;

	private AudioRecord.OnRecordPositionUpdateListener updateListener = new AudioRecord.OnRecordPositionUpdateListener() {
		public void onMarkerReached(AudioRecord recorder) {
			Log.i("AUDIO", "onMarkerReached");
		}

		public void onPeriodicNotification(AudioRecord recorder) {
			Log.i("AUDIO", "onPeriodicNotification");
			if (isRecording) {
				int length = audioRecord.read(buffer, 0, buffer.length); // Fill
																			// buffer
//				sendPieceDataToServer("data".getBytes(), "data".length());
				sendPieceDataToServer(getByteToSend(buffer, AUDIO_DATA), buffer.length);
				payloadSize += buffer.length;
			}
		}
	};

	protected boolean isBound = false;

	protected Messenger mService; 
	
	private final Messenger mMessenger = new Messenger(new IncomingHandler());

	private class IncomingHandler extends Handler {
		@Override
		public void handleMessage(Message msg) {
			switch (msg.what) {
				case MusicService.MSG_NOWPLAYING_TRACK :
					
					Bundle b = new Bundle();
					b = msg.getData(); 
					nowPlagTrackTV.setText(b.getString(MusicService.CURRENT_NOW_PLAYING_TRACK));
					nowPlagArtistTV.setText(b.getString(MusicService.CURRENT_NOW_PLAYING_ARTIST));
					Log.i("SERVICE", "MAINACTIVITY : " + b.getString(MusicService.CURRENT_NOW_PLAYING_TRACK));
					break;
			 
				default:
					super.handleMessage(msg);
			}
		}
	}
		
	private ServiceConnection serviceConnection = new ServiceConnection() {
		
		@Override
		public void onServiceDisconnected(ComponentName name) {  
			mService = null; 
			isBound = false;
		}
		
		@Override
		public void onServiceConnected(ComponentName name, IBinder service) { 
			mService = new Messenger(service);
			isBound = true; 
			try {
                Message msg = Message.obtain(null, MusicService.MSG_REGISTER_MAIN_ACTIVITY);
                msg.replyTo = mMessenger;
                mService.send(msg);
            } catch (RemoteException e) {
                // In this case the service has crashed before we could even do anything with it
            }
			Log.i("SERVICE", "Main activity is connected");
		}
	};
	
	private void doBindService() {
		Log.i("SERVICE", "MAINACTIVITY do bind Service");
		if (MusicService.isRunning) {
			Intent intent = new Intent(this, MusicService.class);
			if (!bindService(intent, serviceConnection,  Context.BIND_AUTO_CREATE)) {
				Log.e("SERVICE", "don't bind Service");
			}
			Log.i("SERVICE", "MAINACTIVITY bind Service");
		}
	}
    
	private void doUnbindService() {
		 if (isBound) {
			 unbindService(serviceConnection);
			 isBound = false;
		 }
	}
	
	
	
	public MainActivity() {

	}

	private void initPropertiesAudio() {
		framePeriod = (int) (sampleRate * TIMER_INTERVAL / 1000);
		bufferSize = framePeriod * 2 * bitsPerSample * nChannels / 8;
		if (bufferSize < AudioRecord.getMinBufferSize(RECORDER_SAMPLERATE,
				RECORDER_CHANNELS, RECORDER_AUDIO_FORMAT)) {
			Log.i("AUDIO", "bufferSize counted : " + bufferSize);
			bufferSize = AudioRecord.getMinBufferSize(RECORDER_SAMPLERATE,
					RECORDER_CHANNELS, RECORDER_AUDIO_FORMAT);

		}
		Log.i("AUDIO", "final bufferSize : " + bufferSize + " framePeriod : "
				+ framePeriod);
		buffer = new byte[bufferSize];
//		audioRecord = new AudioRecord(AudioSource.MIC, RECORDER_SAMPLERATE,
//				RECORDER_CHANNELS, RECORDER_AUDIO_FORMAT, bufferSize);
//		audioRecord.setRecordPositionUpdateListener(updateListener);
//		audioRecord.setPositionNotificationPeriod(framePeriod);
	}

	private void initSocket() {
		try {
			udpSocket = new DatagramSocket(8080);
			serverAddress = InetAddress.getByName(SERVER_IP);
		} catch (SocketException e) { // TODO Auto-generated catch block
			e.printStackTrace();
		} catch (UnknownHostException e) {

		}
	}

	@Override
	protected void onCreate(Bundle bundle) {
		super.onCreate(bundle);
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		setContentView(R.layout.main_activity);
		context = this;
		Log.i(ACTIVIY_LOG, "MainActivity_Create");

		FragmentPagerAdapter adapter = new MusicAdapter(
				getSupportFragmentManager());
		pager = (ViewPager) findViewById(R.id.pager);
		pager.setAdapter(adapter);
		TitlePageIndicator indicator = (TitlePageIndicator) findViewById(R.id.indicator);
		indicator.setViewPager(pager);

		Intent i = new Intent(this, MusicService.class);
		startService(i);
		doBindService();

		initPropertiesAudio();

		ImageButton nowPlayingBT = (ImageButton) findViewById(R.id.now_playing_bt);
		nowPlayingBT.setOnClickListener(openNowPlayingAcListener);
		
		
		nowPlagTrackTV = (TextView)findViewById(R.id.now_playing_track_on_main); 
		nowPlagArtistTV = (TextView)findViewById(R.id.now_playing_artist_on_main); 
		nowPlagTrackTV.setOnClickListener(openNowPlayingAcListener);
		nowPlagArtistTV.setOnClickListener(openNowPlayingAcListener);
		ImageButton searchImgBt = (ImageButton) findViewById(R.id.voice_search_on_main);
		searchImgBt.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				// startRecording();
				// show dialog
				// createDialog().show();
				isRecording = true;
				startRecoringStream();
//				new CountDownTimer(5000, 1000) {
//					
//					@Override
//					public void onTick(long millisUntilFinished) {
//						// TODO Auto-generated method stub
//						
//					}
//					
//					@Override
//					public void onFinish() {
//						// TODO Auto-generated method stub
//						stopRecording();
//					}
//				}.start();
			}
		});

	}

	private OnClickListener openNowPlayingAcListener = new OnClickListener() {
		
		@Override
		public void onClick(View arg0) {
			if (MusicService.trackList.size() > 0) {
				Intent intent = new Intent(getApplicationContext(),
						NowPlayingActivity.class); 
				startActivity(intent);
			} else {
				Toast.makeText(context, "Vui lòng chọn bài hát",
						Toast.LENGTH_SHORT).show();
			}

		}
	};
	
	TextView timeTV;

	private Dialog createDialog() {
		final Dialog dialog = new Dialog(context);
		dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
		dialog.setContentView(R.layout.dialog_recording);
		timeTV = (TextView) dialog.findViewById(R.id.time_tv);

		final Thread t = new Thread() {
			public void run() {
				isRecording = true;
//				startRecording();
//				int waited = 0;
//				while (waited < timeToRecord * 1000) {
//					try {
//						Thread.sleep(100); 
//					} catch (InterruptedException e1) { // TODO Auto-generated
//														// catch block
//						e1.printStackTrace();
//					}
//					runOnUiThread(new Runnable() { 
//						@Override
//						public void run() {
////							timeTV.setText("");
//						}
//					});
//					waited += 100;
//				}

			};
		};

		t.start();
		return dialog;

	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.activity_main, menu);
		return true;
	}

	@Override
	protected void onDestroy() {
		Log.i(ACTIVIY_LOG, "mainActivity_Destroy");
		doUnbindService();
		stopService(new Intent(this, MusicService.class));
		super.onDestroy();
		MusicService.trackList.clear();
	}

	@Override
	public boolean onKeyDown(int keyCode, KeyEvent event) {
		if (keyCode == KeyEvent.KEYCODE_BACK) {
			this.finish();
		}

		return super.onKeyDown(keyCode, event);
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {

		switch (item.getItemId()) {
		case R.id.menu_settings:
			startActivity(new Intent(context, PrefsActivity.class));
		default:
			return super.onOptionsItemSelected(item);
		}
	}

	@Override
	protected void onPause() {
		Log.i(ACTIVIY_LOG, "MainActivity_Pause");
		super.onPause();
		songlist.clear();
	}

	@Override
	protected void onResume() {
		Log.i(ACTIVIY_LOG, "MainActivity_onResum");
		super.onResume();
		
	}

	@Override
	protected void onStart() {
		Log.i(ACTIVIY_LOG, "MainActivity_onStart");
		super.onStart();
	}

	@Override
	protected void onStop() {
		Log.i(ACTIVIY_LOG, "MainActivity_Stop");
		super.onStop(); 
	}

	private void sendPieceDataToServer(byte[] b, int length) {
		if (udpSocket.isClosed()) return;
		if (udpSocket == null) return;
		DatagramPacket packet = new DatagramPacket(b, length);
		packet = new DatagramPacket(b, length, serverAddress, SERVER_PORT);
		try {
			udpSocket.send(packet);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	private void startRecoringStream() {
		
		 streamThread.start();
	}
	
	 Thread streamThread = new Thread(new Runnable() {

         @Override
         public void run() {
			try {
				DatagramSocket udpSocket2 = new DatagramSocket(8080);
				InetAddress serverAddress2 = InetAddress.getByName(SERVER_IP);
				DatagramPacket packet = null;
				audioRecord = new AudioRecord(AudioSource.MIC, RECORDER_SAMPLERATE,
						RECORDER_CHANNELS, RECORDER_AUDIO_FORMAT, bufferSize);
				
				audioRecord.startRecording();
				int readData = audioRecord.read(buffer, 0, buffer.length);
				payloadSize += readData;
				final Timer t = new Timer();
				t.schedule(new TimerTask() {
					int count = timeToRecord;
					@Override
					public void run() {   
						if (count == 0) {
							isRecording = false;
							stopRecordingStream();
							t.cancel();
						} 
						Log.i("AUDIO", "" + count--);
					}
				}, 0, 1000);
				while(isRecording) {
					packet = new DatagramPacket(buffer, readData, serverAddress2, SERVER_PORT);
					udpSocket2.send(packet);
					Log.i("AUDIO", "Recoring..." + payloadSize);
				} 		
				
				
			} catch (Exception e) { 
				 Log.e(MainActivity.class.getName(), e.toString());
			}
         }
	 });
	 
	long hientai;
	private void startRecording() {
//		if (audioRecord == null) { 
//			audioRecord = new AudioRecord(AudioSource.MIC, RECORDER_SAMPLERATE,
//					RECORDER_CHANNELS, RECORDER_AUDIO_FORMAT, bufferSize);
//			audioRecord.setRecordPositionUpdateListener(updateListener);
//			audioRecord.setPositionNotificationPeriod(framePeriod);
//		}

		if (udpSocket == null) {
			 initSocket();
		}
		
		
		
		
//		byte[] send = "LÃª Quang LiÃªn".getBytes();
//		int sendlen = "LÃª Quang LiÃªn".getBytes().length;
//		
//		byte [] result = new byte[sendlen + 1];
//		result[0] = SEARCH_TYPE;
//		System.arraycopy(send, 0,  
//				result, 1, sendlen); 
		
		byte[] result = getByteToSend("LÃª Quang LiÃªn".getBytes(), SEARCH_TYPE);
		
		sendPieceDataToServer(result, result.length);

		isRecording = true;
		Log.i("AUDIO", "Starting recording...");
		// stopRecording();
		audioRecord.startRecording();
		audioRecord.read(buffer, 0, bufferSize);
		hientai = System.currentTimeMillis();
		final Timer t = new Timer();
		t.schedule(new TimerTask() {
			int count = timeToRecord;
			@Override
			public void run() {   
				if (count == 0) {
					stopRecording();
					t.cancel();
				} 
				Log.i("AUDIO", "" + count--);
			}
		}, 0, 1000);
	}

	private void stopRecording() {
		if (audioRecord != null) {
			audioRecord.stop();
			audioRecord.release();
			audioRecord.setRecordPositionUpdateListener(null);
			audioRecord = null;
			isRecording = false;
			Log.i("AUDIO", "Recording time : " + (System.currentTimeMillis() - hientai)/1000 + 
					",Payload : " + payloadSize);
			Log.i("AUDIO", "Stopped recording"); 
			sendPieceDataToServer(getByteToSend(toBytes(payloadSize), PAYLOAD_SIZE),toBytes(payloadSize).length );
			//
			if (udpSocket != null || !udpSocket.isClosed()) {
				udpSocket.close();
				udpSocket = null;
			}
		}
	}
	
	private void stopRecordingStream() {
		if (audioRecord != null) {
			audioRecord.stop();
			audioRecord.release();
			audioRecord.setRecordPositionUpdateListener(null);
			audioRecord = null;
			try {
				DatagramSocket udpSocket2 = new DatagramSocket(8080);
				InetAddress serverAddress2 = InetAddress.getByName(SERVER_IP);
				DatagramPacket packet = null; 
				packet = new DatagramPacket(getByteToSend(toBytes(payloadSize), PAYLOAD_SIZE), getByteToSend(toBytes(payloadSize), PAYLOAD_SIZE).length,
						serverAddress2, SERVER_PORT);
				udpSocket2.send(packet); 
			}catch (Exception e) { 
				 Log.e(MainActivity.class.getName(), e.toString());
			}
			
			
		}
	}

	byte[] toBytes(int i) {
		byte[] result = new byte[4];

		result[0] = (byte) (i >> 24);
		result[1] = (byte) (i >> 16);
		result[2] = (byte) (i >> 8);
		result[3] = (byte) (i /* >> 0 */);

		return result;
	}
	
	byte[] getByteToSend(byte [] src, byte type) {
		int srcLen = src.length;
		byte [] result = new byte[srcLen + 1];
		result[0] = type;
		System.arraycopy(src, 0, result, 1, srcLen); 
		return result;
	}
	
}
